﻿using System;
using System.Web.Mvc;


namespace Wayloop.Web.Mvc
{
    public class AreaViewEngine : WebFormViewEngine
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AreaViewEngine"/> class.
        /// </summary>
        public AreaViewEngine()
        {
            MasterLocationFormats = new[] {
                "~/Views/{0}.master",
                "~/Views/{1}/{0}.master",
                "~/Views/Shared/{0}.master"
            };

            ViewLocationFormats = new[] {
                "~/Views/{0}.aspx",
                "~/Views/{0}.ascx",
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx",
                "~/Views/Shared/{0}.aspx",
                "~/Views/Shared/{0}.ascx"
            };

            PartialViewLocationFormats = ViewLocationFormats;
        }


        /// <summary>
        /// Finds the partial view.
        /// </summary>
        /// <param name="controllerContext">The controller context.</param>
        /// <param name="partialViewName">Partial name of the view.</param>
        /// <param name="useCache">if set to <c>true</c> [use cache].</param>
        /// <returns>The partial view.</returns>
        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            ViewEngineResult areaResult;

            if (controllerContext.RouteData.Values.ContainsKey("area")) {
                string areaPartialName = FormatViewName(controllerContext, partialViewName);
                areaResult = base.FindPartialView(controllerContext, areaPartialName, useCache);

                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }

                string sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
                areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName, useCache);

                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
            }

            return base.FindPartialView(controllerContext, partialViewName, useCache);
        }


        /// <summary>
        /// Finds the view.
        /// </summary>
        /// <param name="controllerContext">The controller context.</param>
        /// <param name="viewName">Name of the view.</param>
        /// <param name="masterName">Name of the master.</param>
        /// <param name="useCache">if set to <c>true</c> [use cache].</param>
        /// <returns>The page view.</returns>
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            ViewEngineResult areaResult;

            if (controllerContext.RouteData.Values.ContainsKey("area")) {
                string areaViewName = FormatViewName(controllerContext, viewName);
                areaResult = base.FindView(controllerContext, areaViewName, masterName, useCache);

                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }

                string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
                areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName, useCache);

                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
            }

            return base.FindView(controllerContext, viewName, masterName, useCache);
        }


        private static string FormatViewName(ControllerContext controllerContext, string viewName)
        {
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string areaName = controllerContext.RouteData.Values["area"].ToString();

            return String.Concat(areaName, "/", controllerName, "/", viewName);
        }


        private static string FormatSharedViewName(ControllerContext controllerContext, string viewName)
        {
            string areaName = controllerContext.RouteData.Values["area"].ToString();

            return String.Concat(areaName, "/Shared/", viewName);
        }
    }
}